﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace Liquid.Windows {
	public class ProgressIndicator : Control {
		#region Fields (5)

		int m_AnimationStep;
		int m_MaxAnimationStep;
		GraphicsPath m_OuterPath;
		GraphicsPath m_InnerPath;
		PathGradientBrush m_Gradient;
		Timer m_Timer;

		#endregion Fields

		#region Constructors (2)

		public ProgressIndicator() {
			SetStyle(ControlStyles.SupportsTransparentBackColor, true);
			SetStyle(ControlStyles.UserPaint, true);
			SetStyle(ControlStyles.AllPaintingInWmPaint, true);
			SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
			m_Timer = new Timer { Interval = 50 };
			m_Timer.Tick += new EventHandler(m_Timer_Tick);
		}

		protected override void OnResize(EventArgs e) {
			RecreatePaths();
		}

		private void RecreatePaths() {
			if (m_OuterPath != null) m_OuterPath.Dispose();
			if (m_InnerPath != null) m_InnerPath.Dispose();
			if (m_Gradient != null) m_Gradient.Dispose();
			m_OuterPath = new GraphicsPath();
			m_OuterPath.AddEllipse(0, 0, Width, Height);
			m_OuterPath.Flatten(new Matrix(), 0.125f);
			m_InnerPath = new GraphicsPath();
			m_InnerPath.AddEllipse(0, 0, Width, Height);
			m_InnerPath.AddEllipse(5, 5, Width - 10, Height - 10);

			m_Gradient = new PathGradientBrush(m_OuterPath);
			var baseColor = this.ForeColor;
			m_Gradient.CenterColor = baseColor;
			m_AnimationStep = 0;
			m_MaxAnimationStep = m_OuterPath.PointCount;
			SetColorsForAnimationStep();
		}

		private void SetColorsForAnimationStep() {
			var step = m_AnimationStep;
			var max = m_MaxAnimationStep;
			var baseColor = this.ForeColor;
			var colors = new Color[max];
			for (int i = 0; i < max; i++) {
				colors[(i + step) % max] = Color.FromArgb(
					(int)((i / (float)max) * 255),
					baseColor
				);
			}
			m_Gradient.SurroundColors = colors;
		}

		protected override void Dispose(bool disposing) {
			if (m_OuterPath != null) m_OuterPath.Dispose();
			if (m_InnerPath != null) m_InnerPath.Dispose();
			if (m_Gradient != null) m_Gradient.Dispose();
			if (m_Timer != null) m_Timer.Dispose();
		}

		#endregion Constructors

		#region Properties (2)

		public bool Running {
			get { return m_Timer.Enabled; }
		}

		#endregion Properties

		#region Methods (6)


		// Public Methods (3) 

		public override Size GetPreferredSize(Size proposedSize) {
			return new Size(32, 32);
		}

		public void Start() {
			m_Timer.Start();
			Invalidate();
		}

		public void Stop() {
			m_Timer.Stop();
			Invalidate();
		}

		// Protected Methods (1) 

		protected override void OnPaint(PaintEventArgs e) {
			var g = e.Graphics;
			var oldMode = g.SmoothingMode;
			g.SmoothingMode = SmoothingMode.HighQuality;
			if (m_Gradient == null)
				RecreatePaths();
			if (m_Timer.Enabled) {
				e.Graphics.FillPath(m_Gradient, m_InnerPath);
			} else {
				using (var brush = new SolidBrush(Color.FromArgb(32, ForeColor)))
					e.Graphics.FillPath(brush, m_InnerPath);
			}
			g.SmoothingMode = oldMode;
		}



		// Private Methods (2) 

		void m_Timer_Tick(object sender, EventArgs e) {
			m_AnimationStep += 1;
			m_AnimationStep %= m_MaxAnimationStep;
			SetColorsForAnimationStep();
			this.Invalidate();
		}

		#endregion Methods

	}
}
